﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Genuilder.Extensibility
{
	public struct Location
	{
		public static int GetIndex(Location location, String text)
		{
			int currentIndex = 0;
			for(int i = 0; i < location.Line - 1; i++)
			{
				currentIndex = text.IndexOf(Environment.NewLine, currentIndex);
				currentIndex += Environment.NewLine.Length;
			}
			currentIndex += location.Column - 1;
			return currentIndex;
		}

		public static Location GetLocation(int index, String text)
		{
			if(index >= text.Length || index < 0)
			{
				throw new IndexOutOfRangeException("index : " + index);
			}
			text = text.Substring(0, index + 1);
			var enumerableChar = (IEnumerable<char>)text;
			text = new String(text.Reverse().ToArray());
			int columnNumber = text.IndexOf(new String(Environment.NewLine.Reverse().ToArray()));
			if(columnNumber == -1)
			{
				columnNumber = text.Length - 1;
			}
			else
			{
				columnNumber--;
			}
			int lineNumber = text.Split(new[] { new String(Environment.NewLine.Reverse().ToArray()) }, StringSplitOptions.None).Length - 1;
			return new Location(lineNumber + 1, columnNumber + 1);
		}

		public static String GetTextBetween(Location from, Location to, String text)
		{
			int indexFrom = GetIndex(from, text);
			int indexTo = GetIndex(to, text);
			return text.Substring(indexFrom, indexTo - indexFrom);
		}

		public override string ToString()
		{
			return "Line : " + line + " Column : " + column;
		}

		public Location(int line, int column)
		{
			AssertGreaterOrEqualToZero("line", line);
			AssertGreaterOrEqualToZero("column", column);
			this.column = column;
			this.line = line;
		}

		public static Location operator +(Location a, Location b)
		{
			return new Location(a.Line + b.Line, a.Column + b.Column);
		}

		static void AssertGreaterOrEqualToZero(string paramName, int value)
		{
			if(value < 0)
			{
				throw new ArgumentException(paramName + " should be greater or equal to 0");
			}
		}

		public static bool operator <(Location a, Location b)
		{
			if(a.Line < b.Line)
			{
				return true;
			}

			if(a.Line > b.Line)
			{
				return false;
			}

			return a.Column < b.Column;
		}

		public static bool operator >(Location a, Location b)
		{
			return a < b == false && !a.Equals(b);
		}

		readonly int column;

		public int Column
		{
			get
			{
				return column;
			}
		}

		readonly int line;

		public int Line
		{
			get
			{
				return line;
			}
		}

	}
}
